#include "document.h"
#include "gameobjects/texture.h"
#include "gameobjects/animation.h"
#include "gameobjects/graphicsobject.h"

#include "serialization/documentsaver.h"
#include "serialization/documentloader.h"

#include "physics/collisionshapes.h"

Document::Document(QObject *parent) :
    QObject(parent)
  , m_bModified(false)
{
}

bool Document::isModified() const
{
    return m_bModified;
}

void Document::setModified(bool bValue)
{
    if(m_bModified == bValue) return;
    m_bModified = bValue;
    emit modifiedStateChanged(m_bModified);
}

QPointer<GraphicsObject> Document::createGraphicsObject(const QString &id)
{
    QPointer<GraphicsObject> newObject = new GraphicsObject(this);
    newObject->setID(id);
    m_objects.append(newObject);
    emit objectCreated(qobject_cast<AbstractObject*>(newObject));
    setModified(true);
    return newObject;
}

QPointer<Animation> Document::createAnimation(const QString &id, QPointer<GraphicsObject> parent)
{
    QPointer<Animation> newAnim = new Animation(parent);
    newAnim->setID(id);
    parent->addAnimation(newAnim);
    newAnim->setParentObject(qobject_cast<AbstractObject*>(parent));
    emit objectCreated(qobject_cast<AbstractObject*>(newAnim));
    setModified(true);
    return newAnim;
}

QPointer<Texture> Document::createTexture(const QString &id, QPointer<AbstractObject> parent, const QString &path)
{
    QPointer<Texture> newTex = new Texture(parent);
    newTex->setID(id);
    if(!path.isEmpty())
    {
        newTex->setFileName(path);
    }

    if(QPointer<GraphicsObject> go = qobject_cast<GraphicsObject*>(parent))
    {
        go->setTexture(newTex);
    }
    else if(QPointer<Animation> anim = qobject_cast<Animation*>(parent))
    {
        anim->setTexture(newTex);
    }
    else
    {
        Q_ASSERT(false);
    }


    newTex->setParentObject(parent);
    emit objectCreated(qobject_cast<AbstractObject*>(newTex));
    setModified(true);
    return newTex;
}

QPointer<CollisionShape> Document::createRectShape(const QRectF &rect)
{
    QPointer<CollisionShape> shape = new CollisionBox(rect);

    return shape;
}

QPointer<CollisionShape> Document::createCircleShape(const QPointF &center, float radius)
{
    QPointer<CollisionShape> shape = new CollisionCircle(center, radius);

    return shape;
}

QPointer<CollisionShape> Document::createPolyShape(const QPolygonF &poly)
{
    QPointer<CollisionShape> shape = new CollisionPoly(poly);

    return shape;
}

bool Document::deleteObject(QPointer<AbstractObject> object)
{
    bool bResult = false;

    QPointer<AbstractObject> po = object->parentObject();

    if(!po && m_objects.contains(qobject_cast<GraphicsObject*>(object)))
    {
        m_objects.removeOne(qobject_cast<GraphicsObject*>(object));
        emit objectDeleted(object);
        object->deleteLater();
        bResult = true;
    }
    else
    {
        if(QPointer<Texture> tex = qobject_cast<Texture*>(object))
        {
            // check which object is parent
            if(QPointer<GraphicsObject> go = qobject_cast<GraphicsObject*>(po))
            {
                tex->deleteLater();
                go->setTexture(0);
                emit objectDeleted(qobject_cast<AbstractObject*>(tex));
                bResult = true;
            }
            else if(QPointer<Animation> ao = qobject_cast<Animation*>(po))
            {
                tex->deleteLater();
                ao->setTexture(0);
                emit objectDeleted(qobject_cast<AbstractObject*>(tex));
                bResult = true;
            }
        }
        else if(QPointer<Animation> anim = qobject_cast<Animation*>(object))
        {
            QPointer<GraphicsObject> go = qobject_cast<GraphicsObject*>(po);
            go->removeAnimation(anim);
            anim->deleteLater();
            emit objectDeleted(qobject_cast<AbstractObject*>(anim));
            bResult = true;
        }
    }
    return bResult;
}

QString Document::currentFileName() const
{
    return m_currentFileName;
}

void Document::setCurrentFileName(QString fileName)
{
    m_currentFileName = fileName;
    emit currentFilenameChanged(fileName);
}

QPointer<AbstractObject> Document::currentObject() const
{
    return m_currentObject;
}

bool Document::isEmpty() const
{
    return m_objects.isEmpty();
}

QList<QPointer<GraphicsObject> > Document::graphicsObjects() const
{
    return m_objects;
}

void Document::setCurrentObject(QPointer<AbstractObject> object)
{
    if(m_currentObject == object) return;
    m_currentObject = object;
    emit currentObjectChanged(m_currentObject);
}
